/*
// SoftwarePackage.cs
// 
// Copyright (C) 2003-2004 Ryan Seghers
//
// This software is provided AS IS. No warranty is granted, 
// neither expressed nor implied. USE THIS SOFTWARE AT YOUR OWN RISK.
// NO REPRESENTATION OF MERCHANTABILITY or FITNESS FOR ANY 
// PURPOSE is given.
//
// License to use this software is limited by the following terms:
// 1) This code may be used in any program, including programs developed
//    for commercial purposes, provided that this notice is included verbatim.
//    
// Also, in return for using this code, please attempt to make your fixes and
// updates available in some way, such as by sending your updates to the
// author.
//

using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Diagnostics;
using Microsoft.Win32;

namespace RTools_NTS.Util
{
/// <summary>
/// This class represents an installed software package on a Windows
/// system.  This has some static utility methods that will get the
/// list of installed software packages, letting you uninstall one.
/// </summary>
/// <remarks>
/// <para>This is motivated by the desire to get the version of an installed
/// package, and by the fact that I wasn't able to find an easier way to 
/// uninstall an Msi by product name (msiexec needs the product code).
/// </para>
/// <para>
/// This looks for uninstallable packages in the registry in:
/// HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall
/// </para>
/// </remarks>
public class SoftwarePackage
{
    #region Fields

    private string name;
    private string productCode;
    private string uninstallString;
    private string displayVersion;

    #endregion 

    #region Properties

    /// <summary>Product name.</summary>
    public string Name { get { return(name); } set { name = value; } }

    /// <summary>Product Code.</summary>
    public string ProductCode { get { return(productCode); } set { productCode = value; } }

    /// <summary>Uninstall string (a shell command to use to remove this SoftwarePackage).</summary>
    public string UninstallString 
    { 
        get 
        { 
            if (uninstallString != string.Empty)
                return(uninstallString); 
            else if (productCode != string.Empty)
            {
                return("msiexec.exe /I" + productCode);
            }
            else return(string.Empty);
        } 
        set { uninstallString = value; } 
    }

    /// <summary>The DisplayVersion for this SoftwarePackage.</summary>
    public string DisplayVersion { get { return(displayVersion); } set { displayVersion = value; } }

    /// <summary>Whether or not this SoftwarePackage is uninstallable (by this class).</summary>
    public bool IsUninstallable
    {
        get
        {
            if ((UninstallString != string.Empty) 
                || (productCode != string.Empty)) return(true);
            else return(false);
        }
    }

    #endregion

    #region Constructors

    /// <summary>
    /// Default constructor.
    /// </summary>
    public SoftwarePackage()
    {
        name = string.Empty;
        productCode = string.Empty;
        uninstallString = string.Empty;
        displayVersion = string.Empty;
    }

    /// <summary>
    /// Constructor which sets all values.
    /// </summary>
    /// <param name="name">The product name.</param>
    /// <param name="productCode">The ProductCode.</param>
    /// <param name="uninstallString">The uninstall string.</param>
    /// <param name="displayVersion">The display version.</param>
    public SoftwarePackage(string name, string productCode, string uninstallString,
        string displayVersion)
    {
        if (name != null) this.name = name;
        else this.name = string.Empty;

        if (productCode != null) this.productCode = productCode;
        else this.productCode = string.Empty;

        if (uninstallString != null) this.uninstallString = uninstallString;
        else this.uninstallString = string.Empty;

        if (displayVersion != null) this.displayVersion = displayVersion;
        else this.displayVersion = string.Empty;
    }

    #endregion

    #region main Instance Methods

    /// <summary>
    /// Uninstall this setup.
    /// </summary>
    /// <param name="interactive">Whether or not to use the interactive
    /// interface.</param>
    /// <returns>bool - true for success, false for failure</returns>
    public bool Uninstall(bool interactive)
    {
        Process p = null;
        ProcessStartInfo psi = null;
			
        // build process start info
        string cmdLine;

        if (uninstallString == string.Empty) 
        {
            // no specific uninstall string, use mine
            if (productCode == String.Empty) return(false);
            cmdLine = "/x" + ProductCode + (interactive ? " /qf" : " /qb");
            psi = new ProcessStartInfo("msiexec.exe", cmdLine);
        }
        else if (uninstallString.ToLower().IndexOf("msiexec") >= 0)
        {
            // it's an msiexec command, try to enact the interactive spec
            if (productCode == String.Empty) cmdLine = uninstallString;
            else 
            {
                cmdLine = "/x" + ProductCode + (interactive ? " /qf" : " /qb");
                psi = new ProcessStartInfo("msiexec.exe", cmdLine);
            }
        }
        else
        {
            cmdLine = uninstallString;
        }

        // execute
        if (psi != null)
        {
            // Process endCapStyle				
            p = new Process();
            p.StartInfo = psi;
            p.Start();
            int timeoutMs = 2 * 60 * 1000;
            if (interactive) timeoutMs = Int32.MaxValue;
            p.WaitForExit(timeoutMs);
            return(p.ExitCode == 0);
            //return(true);
        }
        else
        {
            // Executor endCapStyle for arbitrary command line
            TempFileCollection tmpFiles = new TempFileCollection(".", false);
            Executor.ExecWait(cmdLine, tmpFiles);
            return(true);
        }
    }

    #endregion

    #region Standard Methods

    /// <summary>
    /// ToString override.
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return(name + ", " + displayVersion + ", uninstallable: "
            + IsUninstallable);
    }

    #endregion

    #region Static Utility Methods

    /// <summary>
    /// This returns an array of potentially unstallable SoftwarePackages.
    /// See SoftwarePackage.IsUninstallable to see whether this class
    /// can uninstall a particular SoftwarePackage.
    /// </summary>
    /// <returns>The SoftwarePackage[], null for error.</returns>
    public static SoftwarePackage[] GetList()
    {
        //
        // registry access
        //
        string uninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
        RegistryKey key = Registry.LocalMachine.OpenSubKey(uninstallKey);
        if (key == null)							
            return null;			

        // list them
        ArrayList list = new ArrayList();
        string[] subkeyNames = key.GetSubKeyNames();
        foreach(string subkey in subkeyNames)
        {
            RegistryKey sk = key.OpenSubKey(subkey);
            string prodName;
            string uninstallString = (string)sk.GetValue("UninstallString");
            string displayVersion = (string)sk.GetValue("DisplayVersion");
            string productCode = string.Empty;

            if (subkey[0] == '{')
            {
                // product code entry
                productCode = subkey;
                prodName = (string)sk.GetValue("DisplayName");
                if (prodName == null) prodName = string.Empty;
            }
            else 
            {
                // entry by name
                prodName = subkey;
            }
            list.Add(new SoftwarePackage(prodName, productCode, uninstallString, displayVersion));
        }
        return((SoftwarePackage[])list.ToArray(typeof(SoftwarePackage)));
    }

    /// <summary>
    /// Get a particular software package, by product name. This returns
    /// the first package found with the specified product name.
    /// </summary>
    /// <param name="productName">The product name of the package to 
    /// get.</param>
    /// <returns>SoftwarePackage</returns>
    public static SoftwarePackage GetPackage(string productName)
    {
        SoftwarePackage[] setups = GetList();
        foreach(SoftwarePackage s in setups)
        {
            if (s.Name.Equals(productName)) return(s);
        }
        return(null);
    }

    /// <summary>
    /// This returns the requested SoftwarePackage only if it only appears 
    /// exactly once (as determined solely by name) in the input SoftwarePackage
    /// array.
    /// </summary>
    /// <param name="name">The product name to look for.</param>
    /// <param name="list">The array of SoftwarePackages to search.</param>
    /// <returns>The SoftwarePackage found, or null for none found or more
    /// than one found.</returns>
    public static SoftwarePackage FindOne(string name, SoftwarePackage[] list)
    {
        SoftwarePackage setup = null;

        foreach(SoftwarePackage s in list)
        {
            if (s.Name.Equals(name)) 
            {
                if (setup != null) return(null);
                setup = s;
            }
        }
        return(setup);
    }

    /// <summary>
    /// Uninstall all uninstallable packages with the specified product name.
    /// </summary>
    /// <param name="productName">The product name of the packages to 
    /// uninstall.</param>
    /// <param name="interactive">Whether to run Msiexec in interactive mode
    /// or not.</param>
    /// <returns>bool - true for 1 or more found and uninstalled, false
    /// otherwise.</returns>
    public static bool UninstallMultiple(string productName, bool interactive)
    {
        SoftwarePackage[] setups = GetList();
        foreach(SoftwarePackage s in setups)
        {
            if (s.Name.Equals(productName) && s.IsUninstallable)
            {
                if (!s.Uninstall(interactive))
                    return(false);
            }
        }
        return(true);
    }

    #endregion	
}
}
*/